//! 成功解析后把 Pair 树格式化成规范 C 风格代码（2 空格缩进；运算符两侧空格）

use pest::iterators::Pair;
use crate::grammar::Rule;

pub fn format_program(pair: Pair<Rule>) -> String {
    let mut out = String::new();
    for p in pair.into_inner() {
        match p.as_rule() {
            Rule::func_def => format_func(p, &mut out),
            _ => {}
        }
    }
    out
}

fn format_func(pair: Pair<Rule>, out: &mut String) {
    out.push_str("int main() ");
    for p in pair.into_inner() {
        if p.as_rule() == Rule::block {
            format_block(p, 0, out);
        }
    }
}

fn format_block(pair: Pair<Rule>, indent: usize, out: &mut String) {
    out.push_str("{\n");
    for p in pair.into_inner() {
        if p.as_rule() == Rule::stmt {
            format_stmt(p, indent + 2, out);
        }
    }
    out.push_str("}\n");
}

fn format_stmt(pair: Pair<Rule>, indent: usize, out: &mut String) {
    let mut inner = pair.into_inner();

    // 空语句 ";"
    let Some(first) = inner.next() else {
        indent_spaces(indent, out);
        out.push_str(";\n");
        return;
    };

    match first.as_rule() {
        Rule::decl_stmt => {
            indent_spaces(indent, out);
            let mut id = "";
            let mut arr: Option<&str> = None;
            let mut init: Option<String> = None;

            for p in first.into_inner() {
                match p.as_rule() {
                    Rule::ident => id = p.as_str(),
                    Rule::array_part => {
                        if let Some(n) = p.into_inner().next() {
                            arr = Some(n.as_str());
                        }
                    }
                    Rule::init_part => {
                        if let Some(e) = p.into_inner().next() {
                            init = Some(fmt_expr(e));
                        }
                    }
                    _ => {}
                }
            }
            out.push_str("int ");
            out.push_str(id);
            if let Some(n) = arr {
                out.push_str(" [");
                out.push_str(n);
                out.push(']');
            }
            if let Some(e) = init {
                out.push_str(" = ");
                out.push_str(&e);
            }
            out.push_str(";\n");
        }
        Rule::return_stmt => {
            indent_spaces(indent, out);
            let expr_s = first.into_inner().next().map(fmt_expr).unwrap_or_default();
            out.push_str("return ");
            out.push_str(&expr_s);
            out.push_str(";\n");
        }
        Rule::expr_stmt => {
            indent_spaces(indent, out);
            let expr_s = first.into_inner().next().map(fmt_expr).unwrap_or_default();
            out.push_str(&expr_s);
            out.push_str(";\n");
        }
        _ => {}
    }
}

/* ---------------- 表达式 ---------------- */

fn fmt_expr(pair: Pair<Rule>) -> String {
    match pair.as_rule() {
        Rule::expr | Rule::add | Rule::mul => {
            // 左结合二元：lhs (op rhs)*
            let mut it = pair.into_inner();
            let Some(first) = it.next() else { return String::new(); };
            let mut s = fmt_expr(first);
            loop {
                let (op, rhs) = (it.next(), it.next());
                match (op, rhs) {
                    (Some(op), Some(rhs)) => {
                        s = format!("{s} {} {}", op.as_str(), fmt_expr(rhs));
                    }
                    _ => break,
                }
            }
            s
        }
        Rule::unary => {
            // unary 的 inner 只有一个：
            //   - child: unary     → 有前缀 '-'：打印成 -<child>
            //   - child: postfix   → 没前缀：直接格式化
            let mut it = pair.into_inner();
            let Some(child) = it.next() else { return String::new(); };
            match child.as_rule() {
                Rule::unary => format!("-{}", fmt_expr(child)),
                Rule::postfix => fmt_expr(child),
                _ => String::new(),
            }
        }
        Rule::postfix => {
            let mut it = pair.into_inner();
            let Some(primary) = it.next() else { return String::new(); };
            let mut s = fmt_expr(primary);
            for idx in it {
                // "[" expr "]"
                if let Some(e) = idx.into_inner().next() {
                    s = format!("{s}[{}]", fmt_expr(e));
                } else {
                    s.push_str("[]");
                }
            }
            s
        }
        Rule::primary => {
            let mut it = pair.into_inner();
            let Some(p) = it.next() else { return String::new(); };
            match p.as_rule() {
                Rule::int_lit | Rule::ident => p.as_str().to_string(),
                Rule::expr => format!("({})", fmt_expr(p)),
                _ => String::new(),
            }
        }
        Rule::ident | Rule::int_lit => pair.as_str().to_string(),
        _ => String::new(),
    }
}

fn indent_spaces(n: usize, out: &mut String) {
    for _ in 0..n { out.push(' '); }
}
